home *** CD-ROM | disk | FTP | other *** search
- /*
- * strip TOS executable format files of symbol table info
- * usage: strip {-g | -k | -l names} [-t] files ...
- *
- * Original version by ++jrb bammi@dsrgsun.ces.cwru.edu
- * (i.e. Jwahar Bammi)
- * Modified to add extra options -g -k and -l by
- * Michal Jaegermann ntomczak@ualtavm.bitnet
- * November 1st, 1990
- *
- * -g keep all global symbols
- * -k keep _stksize symbol, so stack size can be adjusted
- * even for nearly-stripped gcc produced executables
- * -l nms keep all symbols listed in a file 'nms'
- * -t remove additional data from end of file
- *
- * Modified sources compile both with gcc and Sozobon C
- *
- * Added code to deal correctly with extended symbols produced
- * by -G option of gcc
- * Both -k and -l options convert extended symbols into
- * regular ones.
- *
- * ++jrb 4/25/91:
- * Macroized the code to take care of WORD_ALIGNED cross environments.
- * Minor fixes for a !atari !gcc compiler.
- *
- * AL 08/02/92: (alexlehm@iti.informatik.th-darmstadt.de)
- * Added -t option to strip TurboC / PureC style executables
- * Support for little endian (BYTE_SWAPed) machines
- */
-
- #include <stdio.h>
- #ifdef atarist
- #include <stat.h>
- #ifdef __GNUC__
- # include <stddef.h>
- # include <memory.h>
- # include <unistd.h>
- #else
- #include <malloc.h>
- extern long lread();
- extern long lwrite();
- extern long lseek();
- #endif
- #endif
-
- #ifdef unix
- # include <sys/stat.h>
- # include <strings.h>
- # define lwrite write
- # define lread read
- extern char *malloc(), *realloc();
- #ifdef linux
- #include <linux/stddef.h>
- #endif
- #else
- # include <string.h>
- # define lwrite _write
- # define lread _read
- #endif
-
- #include <fcntl.h>
-
- #define NEWBUFSIZ 16384L
-
- char mybuf[NEWBUFSIZ];
- char tmpname[128];
-
- #define SYMLEN 8
- #define GST_SYMLEN 22
-
- typedef char symstr_t[GST_SYMLEN];
- symstr_t stklist[] = {"__stksize", "__initial_stack"};
-
- #ifndef __PROTO
- # if __STDC__ || __cplusplus
- # define __PROTO(s) s
- # else
- # define __PROTO(s) ()
- # endif
- #endif
-
- /* function pointer type for the select functions */
- typedef long (*select_fp) __PROTO((int, int, long, symstr_t *));
-
- void usage __PROTO((char *s ));
- int main __PROTO((int argc , char **argv ));
- int strip __PROTO((char *name,symstr_t *nmlist,select_fp select,int cuttrail));
- long copy __PROTO((int from , int to , long bytes ));
- long copy_relo __PROTO((char *name,int from,int to));
- void report __PROTO((char *s ));
- symstr_t *mklist __PROTO((char *fname ));
- long sel_globs __PROTO((int fd , int tfd , long sbytes , symstr_t *nmlist ));
- long sel_listed __PROTO((int fd , int tfd , long sbytes , symstr_t *nmlist ));
- extern char *getenv __PROTO((const char *));
-
- extern void dump_version(char *prog);
- char *progname = "strip";
-
- int
- main (argc, argv)
- int argc;
- char **argv;
- {
- int status = 0;
- int flag = -1;
- int cuttrail = 0;
- symstr_t *nmlist = stklist;
- select_fp select = sel_listed;
- #ifdef atarist
- char *tmpdir;
- register int l;
- #endif
-
- if (argv[0][0] != '\0')
- progname = argv[0];
-
- /* process arguments */
- while (argv++, --argc) {
- if ('-' != **argv)
- break;
- (*argv)++;
- if( **argv=='t' ) {
- cuttrail = 1;
- } else {
- if ((-1) != flag)
- usage ("only one option at a time is accepted\n");
- flag = **argv;
- switch (flag) {
- case 'g':
- select = sel_globs;
- break;
- case 'k':
- nmlist = stklist;
- select = sel_listed;
- break;
- case 'a':
- select = 0;
- break;
- case 'l':
- (*argv)++;
- if ('\0' == **argv) {
- --argc;
- argv++;
- if( argc==0 )
- usage("missing names file\n");
- }
- if ((symstr_t *) NULL == (nmlist = mklist (*argv)))
- usage ("cannot create a list of reserved names\n");
- select = sel_listed;
- break;
- case 'v':
- dump_version(progname);
- exit(0);
- break;
- default:
- usage ("");
- break;
- }
- }
- }
-
- if (argc < 1) {
- usage ("");
- }
-
- #ifdef __GNUC__
- #ifdef atarist
- if ((tmpdir = getenv ("TEMP")) != NULL) {
- strcpy (tmpname, tmpdir);
- l = (int) strlen (tmpname) - 1;
- if (tmpname[l] == '\\' || tmpname[l] == '/')
- tmpname[l] = '\0';
- strcat (tmpname, "/STXXXXXX");
- }
- else
- #endif
- strcpy (tmpname, "/tmp/STXXXXXX");
-
- mktemp (tmpname);
- #else /* not __GNUC__ */
- # ifdef atarist
- if ((tmpdir = getenv ("TEMP")) != NULL) {
- strcpy (tmpname, tmpdir);
- l = (int) strlen (tmpname) - 1;
- if (tmpname[l] != '\\') {
- l++;
- tmpname[l] = '\\';
- }
- l++;
- }
- else {
- l = 0;
- }
- tmpnam (&tmpname[l]);
- # else
- strcpy (tmpname, "/tmp/STXXXXXX");
- mktemp(tmpname);
- # endif
- #endif /* __GNUC__ */
- do {
- status |= strip (*argv++, nmlist, select, cuttrail);
- } while (--argc > 0);
-
- unlink (tmpname);
- return status;
- }
-
- void
- usage (s)
- char *s;
- {
- report (s);
- report ("Usage: strip {-k | -l names | -g | -a} [-t] files ...\n");
- exit (1);
- }
-
- /* define macro for big and function for little endian machines */
- #ifdef BYTE_SWAP
- short swap_short __PROTO((short s));
- long swap_long __PROTO((long l));
- #else
- #define swap_short(s) (s)
- #define swap_long(l) (l)
- #endif
-
- #if (defined(__GNUC__)) && (!defined(unix))
- #include <st-out.h>
- #else
- /* include relevant fragments of <st-out.h> file directly */
-
- struct aexec {
- short a_magic; /* magic number */
- unsigned long a_text; /* size of text segment */
- unsigned long a_data; /* size of initialized data */
- unsigned long a_bss; /* size of uninitialized data */
- unsigned long a_syms; /* size of symbol table */
- unsigned long a_AZero1; /* always zero */
- unsigned long a_AZero2; /* always zero */
- unsigned short a_isreloc; /* is reloc info present */
- };
- #define CMAGIC 0x601A /* contiguous text */
-
- /*
- * Format of a symbol table entry
- */
- struct asym
- {
- char a_name[SYMLEN]; /* symbol name */
- unsigned short a_type; /* type flag */
- unsigned long a_value; /* value of this symbol
- (or sdb offset) */
- };
-
- #define A_GLOBL 0x2000 /* global */
- #define A_LNAM 0x0048 /* extended name */
-
- #endif /* __GNUC__ */
-
- #if !__STDC__ && !__cplusplus
- # ifndef offsetof
- # define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0L)->MEMBER)
- # endif
- # ifndef CROSSHPUX
- typedef unsigned long size_t;
- # endif
- #endif
-
- #ifdef WORD_ALIGNED
- # define SIZEOF_AEXEC ((2*sizeof(short)) + (6*sizeof(long)))
- # define SIZEOF_ASYM ((SYMLEN*sizeof(char)) + sizeof(short) + sizeof(long))
- # define SYM_OFFSET (sizeof(short) + (3*sizeof(long)))
- int read_head __PROTO((int fd, struct aexec *a));
- #else
- # define SIZEOF_AEXEC (sizeof(struct aexec))
- # define SIZEOF_ASYM (sizeof(struct asym))
- # define SYM_OFFSET (offsetof (struct aexec, a_syms))
- #endif
-
- int
- strip (name, nmlist, select, cuttrail)
- char *name;
- symstr_t * nmlist;
- select_fp select;
- int cuttrail;
- {
- register int fd;
- register int tfd;
- register long count, rbytes, sbytes;
- long lbytes, swap_lbytes;
- struct aexec ahead;
- struct stat statb;
-
- if ((fd = open (name, O_RDONLY, 0666)) < 0) {
- perror (name);
- return 2;
- }
- if ((tfd = open (tmpname, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) {
- perror (tmpname);
- close (fd);
- return 4;
- }
- #ifndef WORD_ALIGNED
- if ((count = lread (fd, &ahead, (long) sizeof (ahead)))
- != (long) sizeof (ahead)) {
- #else
- if (read_head (fd, &ahead)) {
- #endif
- perror (name);
- close (tfd);
- close (fd);
- return 8;
- }
- if (swap_short(ahead.a_magic)!=CMAGIC) {
- report (name);
- report (": Bad Magic number\n");
- close (tfd);
- close (fd);
- return 0x10;
- }
- sbytes = swap_long(ahead.a_syms);
- if (0L == sbytes && !cuttrail) {
- report (name);
- report (": Already Stripped\n");
- close (tfd);
- close (fd);
- return 0x20;
- }
- if (lseek (fd, 0L, 0) < 0) {
- report (name);
- report (": seek error\n");
- close (tfd);
- close (fd);
- return 0x40;
- }
- count = SIZEOF_AEXEC + swap_long(ahead.a_text) + swap_long(ahead.a_data);
- if (copy (fd, tfd, count) != count) {
- close (tfd);
- close (fd);
- return 0x80;
- }
- if (NULL == select) { /* remove whole symbol table */
- lbytes = 0L;
- if (lseek (fd, sbytes, 1) < 0) {
- report (name);
- report (": seek error\n");
- close (tfd);
- close (fd);
- return 0x100;
- }
- }
- else {
- lbytes = ( *select )(fd, tfd, sbytes, nmlist);
- }
- if( cuttrail ) {
- if((rbytes = copy_relo(name,fd,tfd))<0) {
- close(tfd);
- close(fd);
- return 0x8000;
- }
-
- if( lread( fd, &cuttrail, 1 )!=1 ) {
- report (name);
- report (": Already Stripped\n");
- close (tfd);
- close (fd);
- return 0x20;
- }
- } else {
- if ((rbytes = copy (fd, tfd, 0x7fffffffL)) < 0) {
- close (tfd);
- close (fd);
- return 0x200;
- }
- }
- if (lseek (tfd, (long)(SYM_OFFSET), 0) < 0) {
- close (tfd);
- close (fd);
- return 0x400;
- }
- swap_lbytes=swap_long(lbytes);
- if (lwrite (tfd, &swap_lbytes, (long)sizeof (lbytes)) !=
- (long) sizeof (lbytes)) {
- close (tfd);
- close (fd);
- return 0x800;
- }
- close (tfd);
- close (fd);
- if (stat (name, &statb) < 0)
- statb.st_mode = 0666;
- if (rename(tmpname, name) == 0) return 0; /* try to rename it */
- if ((fd = open (name, O_WRONLY | O_TRUNC | O_CREAT, statb.st_mode)) < 0) {
- perror (name);
- return 0x1000;
- }
- if ((tfd = open (tmpname, O_RDONLY, 0666)) < 0) {
- perror (tmpname);
- close (fd);
- return 0x2000;
- }
-
- count = SIZEOF_AEXEC + swap_long(ahead.a_text) + swap_long(ahead.a_data) + rbytes + lbytes;
- if (copy (tfd, fd, count) != count) {
- close (tfd);
- close (fd);
- return 0x4000;
- }
- close (tfd);
- close (fd);
- return 0;
- }
-
- /*
- * copy from, to in NEWBUFSIZ chunks upto bytes or EOF whichever occurs first
- * returns # of bytes copied
- */
- long
- copy (from, to, bytes)
- int from, to;
- long bytes;
- {
- register long todo, done = 0L, remaining = bytes, actual;
-
- while (done != bytes) {
- todo = (remaining > NEWBUFSIZ) ? NEWBUFSIZ : remaining;
- if ((actual = lread (from, mybuf, todo)) != todo) {
- if (actual < 0) {
- report ("Error Reading\n");
- return -done;
- }
- }
- if (lwrite (to, mybuf, actual) != actual) {
- report ("Error Writing\n");
- return -done;
- }
- done += actual;
- if (actual != todo) /* eof reached */
- return done;
- remaining -= actual;
- }
- return done;
- }
-
- /* copy TOS relocation table from `from` to `to`. Copy bytes until NUL byte or
- first 4 bytes if == 0l.
- returns length of relocation table or -1 in case of an error */
-
- long
- copy_relo(name,from,to)
- char *name;
- int from,to;
- {
- long res=0;
- long bytes;
- char *end;
- int finished=0;
-
- res=lread( from, mybuf, sizeof(long) );
- if( res!=0 && res!=sizeof(long) ) {
- report( "Error reading\n" );
- return -1;
- }
-
- if( res==0 ) {
- report("Warning: "); /* I think empty relocation tables are allowed,
- report(name); but could cause trouble with certain programs */
- report( ": No relocation table\n" );
- return 0;
- }
- if( lwrite(to,mybuf,res)!=res ) {
- report(name);
- report( ": Error writing\n" );
- return -1;
- }
-
- res=sizeof(long);
- if( *(long*)mybuf == 0 ) return res; /* This is a clean version of an empty
- relocation table */
- while(!finished) {
- if( (bytes=lread(from,mybuf,NEWBUFSIZ))<0 ) {
- report(name);
- report( ": Error reading\n" );
- return -1;
- }
- if( bytes==0 ) {
- report( "Warning: " );
- report(name);
- report( ": Unterminated relocation table\n" );
- return res;
- }
- /* dont know if sozobon has memchr */
- end=memchr(mybuf,0,bytes);
- if(end) {
- bytes=end-mybuf+1;
- finished=1;
- }
- if( lwrite(to,mybuf,bytes)!=bytes ) {
- report(name);
- report(": Error writing\n");
- return -1;
- }
- }
- }
-
- void
- report (s)
- char * s;
- {
- lwrite (2, s, (long) strlen (s));
- }
-
- /*
- * Given a name of a file with reserved symbols create an array of
- * reserved symbol names. To terminate create an entry which starts
- * with a null character.
- */
-
- #define LBUFSIZE 128
- #define NMSTEP 10
-
- symstr_t *
- mklist (fname)
- char * fname;
- {
- FILE *fp;
- symstr_t *list = (symstr_t *) NULL;
- int left = 0;
- int pos = 0;
- int i;
- size_t max_size = 1;
- char lbuf[LBUFSIZE];
- char *in, *out;
-
- #ifdef atarist
- if (NULL == (fp = fopen (fname, "rt"))) {
- #else
- if (NULL == (fp = fopen (fname, "r"))) {
- #endif
- report (fname);
- report (" -- ");
- usage ("cannot open this file\n");
- }
-
- while (NULL != fgets (lbuf, LBUFSIZE, fp)) {
- if (0 == left) {
- max_size += NMSTEP;
- if ((symstr_t *) NULL == list) {
- list = (symstr_t *) malloc ( max_size * sizeof (symstr_t));
- }
- else {
- list = (symstr_t *) realloc ((void *) list,
- max_size * sizeof (symstr_t));
-
- }
- if ((symstr_t *) NULL == list) {
- report ("out of memory making symbol list\n");
- exit (-3);
- }
- left = NMSTEP;
- }
- /* strip all leading white space */
- in = lbuf;
- while (' ' == *in || '\t' == *in)
- in++;
- if ('\n' == *in)
- continue; /* empty line - skip it */
- out = &list[pos][0];
- for (i = GST_SYMLEN; i > 0; --i) {
- if ('\n' == *in || ' ' == *in || '\t' == *in) {
- while (i-- > 0) *out++ = '\0';
- break;
- }
- *out++ = *in++;
- }
- pos++;
- --left;
- } /* while */
- if ((symstr_t *) NULL != list) {
- list[pos][0] = '\0'; /* terminate created list */
- }
- return (list);
- }
-
- /*
- * From a file handle fd to a file handle tfd copy up to 'sbytes' bytes
- * of a symbol table selecting only those symbols which have A_GLOBL
- * flag set. Table nmlist is not really used, but is here for a uniform
- * interface. Returns a number of bytes copied.
- */
- long
- sel_globs (fd, tfd, sbytes, nmlist)
- int fd, tfd;
- long sbytes;
- symstr_t * nmlist;
- {
- long lbytes = 0;
- struct asym cur_sym;
- int cont = 0;
-
- while (sbytes) {
- if ((long)SIZEOF_ASYM != lread (fd, &cur_sym,
- (long)SIZEOF_ASYM)) {
- report ("error on reading symbol table\n");
- break;
- }
- if (0 == cont) { /* if we are not dealing with the second part */
- cont = (0 != (swap_short(cur_sym.a_type) & A_LNAM));
- if (swap_short(cur_sym.a_type) & A_GLOBL) {
- cont = -cont;
- if ((long)SIZEOF_ASYM != lwrite (tfd, &cur_sym,
- (long)SIZEOF_ASYM)) {
- report ("error on writing symbol table\n");
- break;
- }
- lbytes += SIZEOF_ASYM;
- }
- }
- else { /* this was an extended symbol */
- if (cont < 0) { /* if global then write */
- if ((long)SIZEOF_ASYM != lwrite (tfd, &cur_sym,
- (long)SIZEOF_ASYM)) {
- report ("error on writing symbol table\n");
- break;
- }
- lbytes += SIZEOF_ASYM;
- }
- cont = 0;
- }
- sbytes -= SIZEOF_ASYM;
- }
- return (lbytes);
- }
-
- /*
- * From a file handle fd to a file handle tfd copy up to 'sbytes' bytes
- * of a symbol table selecting only those symbols which are on nmlist.
- * Free nmlist if different from a default global one.
- * Returns a number of bytes copied.
- */
- long
- sel_listed (fd, tfd, sbytes, nmlist)
- int fd, tfd;
- long sbytes;
- symstr_t * nmlist;
- {
- long lbytes = 0;
- symstr_t *kname;
- struct asym cur_sym, spare;
-
- if ((symstr_t *) NULL == nmlist)
- return (0L);
-
- while (sbytes) {
- if ((long)SIZEOF_ASYM != lread (fd, &cur_sym,
- (long) SIZEOF_ASYM)) {
- report ("error on reading symbol table\n");
- break;
- }
- for (kname = nmlist; '\0' != **kname; kname++) {
- if (0 == strncmp (&(*kname)[0], &cur_sym.a_name[0], SYMLEN)) {
- if ((A_LNAM & swap_short(cur_sym.a_type)) == A_LNAM) { /* if extended */
- if ((long)SIZEOF_ASYM != lread (fd, &spare,
- (long)SIZEOF_ASYM)) {
- report ("error on reading symbol table\n");
- goto leave; /* skip two loop levels */
- }
- sbytes -= SIZEOF_ASYM;
- if (strncmp (&(*kname)[SYMLEN], (char *)&spare,
- GST_SYMLEN-SYMLEN))
- continue;
- }
- if ((long)SIZEOF_ASYM != lwrite (tfd, &cur_sym,
- (long)SIZEOF_ASYM)) {
- report ("error on writing symbol table\n");
- goto leave;
- }
- if ((swap_short(cur_sym.a_type) & A_LNAM) == A_LNAM)
- {
- if (lwrite (tfd, &spare, (long)SIZEOF_ASYM) != SIZEOF_ASYM)
- {
- report ("error on writing symbol table\n");
- goto leave;
- }
- lbytes += SIZEOF_ASYM;
- }
- lbytes += SIZEOF_ASYM;
- break;
- }
- } /* for */
- sbytes -= SIZEOF_ASYM;
- } /* while */
- leave:
- if (nmlist != stklist) {
- free (nmlist);
- nmlist = (symstr_t *) NULL;
- }
- return (lbytes);
- }
-
- #ifdef WORD_ALIGNED
- /*
- * read header -- return !0 on err
- */
- #define ck_read(fd, addr, siz) \
- if((long)siz != lread(fd, addr, (long)siz)) return !0;
-
- int read_head (fd, a)
- int fd;
- struct aexec *a;
- {
- ck_read(fd, &a->a_magic, sizeof(a->a_magic));
- ck_read(fd, &a->a_text, sizeof(a->a_text));
- ck_read(fd, &a->a_data, sizeof(a->a_data));
- ck_read(fd, &a->a_bss, sizeof(a->a_bss));
- ck_read(fd, &a->a_syms, sizeof(a->a_syms));
- ck_read(fd, &a->a_AZero1, sizeof(a->a_AZero1));
- ck_read(fd, &a->a_AZero2, sizeof(a->a_AZero2));
- ck_read(fd, &a->a_isreloc, sizeof(a->a_isreloc));
-
- return 0;
- }
- #endif
-
-
- #ifdef CROSSHPUX
- char *xmalloc(n)
- unsigned n;
- {
- extern char *malloc();
- char *ret = malloc(n);
-
- if(!ret)
- {
- fprintf(stderr,"Out of memory!\n");
- exit(1);
- }
- return ret;
- }
- #endif
-
- #ifdef BYTE_SWAP
-
- /* these routines work for big endian machines as well, but are not needed */
-
- long swap_long(l)
- long l;
- {
- long l1=l;
- unsigned char *p=(unsigned char *)&l1;
-
- return (long)p[3]|((long)p[2]<<8)|((long)p[1]<<16)|((long)p[0]<<24);
- }
-
- short swap_short(s)
- short s;
- {
- short s1=s;
- unsigned char *p=(unsigned char *)&s1;
-
- return (short)p[1]|((short)p[0]<<8);
- }
-
- #endif
-